package net.kleinhenz.questor.system;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import net.kleinhenz.questor.Questor;
import net.kleinhenz.questor.exceptions.QuestorScriptException;
import bsh.EvalError;
import bsh.Interpreter;

public class Script
{
	private static Interpreter interpreter = null; 
		
	public static boolean eval(String scriptSource, Map<String, Object> variables) throws QuestorScriptException
	{
		interpreter = new Interpreter(); 
		try 
		{  
			attachVariables(interpreter, variables);
			Object result = interpreter.eval(scriptSource);  
			if (result instanceof Boolean)
				return ((Boolean)result).booleanValue();
			else
				throw new QuestorScriptException("Statement does not evaluate to boolean: " + scriptSource);
		}  
		catch (bsh.EvalError e) 
		{  
			throw new QuestorScriptException("Failed executing Questor script.", e);
		}  
	}

	public static Map<String, Object> execute(String scriptSource, Map<String, Object> variables) throws QuestorScriptException
	{
		interpreter = new Interpreter(); 
		try 
		{  
			attachVariables(interpreter, variables);
			interpreter.eval(scriptSource);  
			return resolveVariables(interpreter, variables.keySet());
		}  
		catch (bsh.EvalError e) 
		{  
			throw new QuestorScriptException("Failed executing Questor script.", e);
		}  
	}

	public static Map<String, Object> execute(InputStream scriptSource, Map<String, Object> variables) throws QuestorScriptException
	{
		interpreter = new Interpreter(); 
		InputStreamReader streamReader = new InputStreamReader(scriptSource);
			
		try 
		{  
			attachVariables(interpreter, variables);
			interpreter.eval(streamReader);  
			return resolveVariables(interpreter, variables.keySet());
		}  
		catch (bsh.EvalError e) 
		{  
			throw new QuestorScriptException("Failed executing Questor script.", e);
		}  
	}

	public static Map<String, Object> executeFile(QSRFile qsrFile, String path, Map<String, Object> variables) throws QuestorScriptException
	{
		try
		{
			return Script.execute(qsrFile.getInputStream(path), variables);
		}
		catch (IOException e)
		{
			throw new QuestorScriptException("Failed reading script file from QSR.", e);
		}
	}

	public static Map<String, Object> executeFile(String path, Map<String, Object> variables) throws QuestorScriptException
	{
		try
		{
			return Script.execute(Questor.getCurrentGame().getCurrentQSR().getInputStream(path), variables);
		}
		catch (IOException e)
		{
			throw new QuestorScriptException("Failed reading script file from QSR.", e);
		}
	}

	private static Map<String, Object> resolveVariables(Interpreter interpreter, Set<String> keySet) throws EvalError
	{
		Map<String, Object> result = new HashMap<String, Object>();
		for (String key : keySet)
			result.put(key, interpreter.get(key));
		return result;
	}

	private static void attachVariables(Interpreter interpreter, Map<String, Object> variables) throws EvalError
	{
		for (String key : variables.keySet())
			interpreter.set(key, variables.get(key));
	}
}
